/**
 * Copyright (c) 2008, Keisuke Inoue, Syracuse Unviersity
 * All rights reserved.
 *
 */
package edu.syr.iis.web.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import edu.syr.iis.web.model.AssignmentManager;
import edu.syr.iis.web.model.Conversation;
import edu.syr.iis.web.model.ConversationManager;
import edu.syr.iis.web.model.DialogueAct;
import edu.syr.iis.web.model.DialogueActAnalysisLevel;
import edu.syr.iis.web.model.DialogueActDimension;
import edu.syr.iis.web.model.DialogueActDimensionManager;
import edu.syr.iis.web.model.DialogueActLabel;
import edu.syr.iis.web.model.DialogueActLabelManager;
import edu.syr.iis.web.model.DialogueActManager;
import edu.syr.iis.web.model.Message;
import edu.syr.iis.web.model.MessageManager;

/**
 * @author kinoue
 *
 */
public class TemporalModelExporter
{

	static final int FUNCTION = 0; 
	static final int DOMAIN_PART = 1;
	static final int SPEAKER_SENSTIVE = 2;


	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		// speakerSensitive(FUNCTION);
		doIt(DialogueActAnalysisLevel.PART_DOMAIN, false);
		// doIt(DialogueActAnalysisLevel.PART_DOMAIN, true);
	}

	public static void doIt(DialogueActAnalysisLevel level, boolean speakerSensitive)
	{
		DialogueActManager dam = new DialogueActManager();
		DialogueActDimension dimension = null;

		List<String> labels = dam.getDialogueActLabelStrings(level, speakerSensitive);

		if (level != DialogueActAnalysisLevel.FUNCTION)
			labels.add("NA");

		labels.add("END1");
		labels.add("START1");

		System.out.println(labels.size() + " labels are defined.");

		Collection<DialogueAct> dialogueActs = dam.getDialogueActs(false);

		// Just for testing
		//
/* 
		 ConversationManager cm = new ConversationManager();	
		 Conversation c1 = cm.getConversation(229);
		 Collection<DialogueAct> dialogueActs = new HashSet<DialogueAct>();

		 for (Message m: c1.getMessages())
		 {
			dialogueActs.addAll(dam.getDialogueActsByMessage(m, false));
		 }
*/
		// End testing


		int [][] matrix = new int [labels.size()][labels.size()];
		int [][] pmatrix = new int [labels.size()][labels.size()];
		int [][] tpmatrix = new int [labels.size()][labels.size()];
		int grandTotal = 0;
		int percentileTotal = 0; // Just to see if the calculation is right.
		
		System.out.println("Start working on " + dialogueActs.size() + "... (it will take a while)... ");
		int count = 0;
				
		for (DialogueAct da: dialogueActs)
		{
			count++;
			if (count % 100 == 0)
			{ 
				System.out.println(count + " dialogueActs done.."); 
			}
			
			Collection<DialogueAct> nextDas = da.getNextDialogueActs(speakerSensitive);
			Collection<DialogueAct> prevDas = da.getPreviousDialogueActs(speakerSensitive);
						
			String thisLabel = da.getLabelForAnalysis(level, speakerSensitive);
			
			List <String> nextLabels = new ArrayList<String>();
			List <String> prevLabels = new ArrayList<String>();
			
			for (DialogueAct nextDa: nextDas)
				nextLabels.add(nextDa.getLabelForAnalysis(level, speakerSensitive));
			
			for (DialogueAct prevDa: prevDas)
				prevLabels.add(prevDa.getLabelForAnalysis(level, speakerSensitive));

			
			int thisLabelIndex = labels.indexOf(thisLabel);

			if (thisLabelIndex < 0)
			{
				System.out.println("Error with label: " + thisLabel);
			}
			else
			{
				for (String nextLabel: nextLabels)
				{
					int nextLabelIndex = labels.indexOf(nextLabel);

					if (nextLabelIndex < 0)
					{
						System.out.println("Error with label: " + nextLabel);
					}
					else
					{
						matrix[thisLabelIndex][nextLabelIndex]++;
					}
				}
			}

			if (prevLabels.isEmpty())
				matrix[labels.indexOf("START1")][thisLabelIndex]++;
		}
		
		for (int i = 0; i < matrix.length; i++)
			for (int j = 0; j < matrix.length; j++)
				grandTotal += matrix[i][j];
			
			
		for (int i = 0; i < matrix.length; i++)
		{
			int total = 0;
			for (int j = 0; j < matrix.length; j++)
				total += matrix[i][j];

			for (int j = 0; j < matrix.length; j++)
			{
				double p = ((double) matrix[i][j]) / total * 100;
				pmatrix[i][j] = (int) Math.round(p);
				tpmatrix[i][j] = (int) Math.round(((double) matrix [i][j]) / grandTotal * 100);
				percentileTotal += tpmatrix[i][j];
			}
		}

		String[] labelArray = new String[labels.size()];
		labelArray = labels.toArray(labelArray);

		System.out.println("Frequencies: ");
		printMatrix(labelArray, matrix);

		System.out.println("Transition-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		System.out.println("Total-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		
		System.out.println("DOT: ");
		printDot(labelArray, tpmatrix, 10, 1, speakerSensitive);
		
		System.out.println("Grand Total: " + grandTotal);
		System.out.println("Pecentile Total: " + percentileTotal);

	}

	public static void speakerSensitive(int option)
	{
		DialogueActManager dam = new DialogueActManager();
		DialogueActDimension dimension = null;

		if ((option & DOMAIN_PART) != 0)
		{
			System.out.println("Setting the dimension of analysis to Domain...");
			dimension = dam.getDialogueActDimension("Domain");
		}
		else
		{
			System.out.println("Setting the dimension of analysis to Function...");
			dimension = dam.getDialogueActDimension("Function");
		}

		List<DialogueActLabel> dialogueActLabels = dam.getDialogueActLabels(dimension, false);	
		List<String> labels = new ArrayList<String>();

		if ((option & DOMAIN_PART) != 0)
		{
			for (DialogueActLabel dal: dialogueActLabels)
			{
				String libLabel = "L:" + dal.getPartLabelNoSpace();
				String userLabel = "U:"+ dal.getPartLabelNoSpace();

				if (! labels.contains(libLabel)) 
				{
					System.out.println("Adding " + libLabel + "...");
					labels.add(libLabel);
				}
				if (! labels.contains(userLabel)) 
				{
					System.out.println("Adding " + userLabel + "...");
					labels.add(userLabel);
				}
			}
			labels.add("NA");
		} 
		else
		{
			for (DialogueActLabel dal: dialogueActLabels)
			{
				labels.add("L:" + dal.getLabelNoSpace());
				System.out.println("Adding L:" + dal.getLabel() + "...");
				labels.add("U:" + dal.getLabelNoSpace());
				System.out.println("Adding U:" + dal.getLabel() + "...");
			}
		}

		labels.add("END1");
		labels.add("START1");

		System.out.println(labels.size() + " labels are defined.");

		Collection<DialogueAct> dialogueActs = dam.getDialogueActs(false);

		// Just for testing
		//
/*
		 ConversationManager cm = new ConversationManager();	
		 Conversation c1 = cm.getConversation(229);
		 Collection<DialogueAct> dialogueActs = new HashSet<DialogueAct>();

		 for (Message m: c1.getMessages())
		 {
			dialogueActs.addAll(dam.getDialogueActsByMessage(m, false));
		 }
*/
		// End testing


		int [][] matrix = new int [labels.size()][labels.size()];
		int [][] pmatrix = new int [labels.size()][labels.size()];
		int [][] tpmatrix = new int [labels.size()][labels.size()];
		int grandTotal = 0;
		int percentileTotal = 0; // Just to see if the calculation is right.
		
		System.out.println("Start working on " + dialogueActs.size() + "... (it will take a while)... ");
		int count = 0;
				
		for (DialogueAct da: dialogueActs)
		{
			count++;
			if (count % 100 == 0)
			{
				System.out.println(count + " dialogueActs done.."); 
			}
			String thisLabel = null;
			Collection<String> nextLabels = null;
			Collection<String> prevLabels = null;

			if ((option & DOMAIN_PART) != 0)
			{
				thisLabel = da.getPartDomainLabel();
				nextLabels = da.getNextDialogueActPartDomainLabels();
				prevLabels = da.getPreviousDialogueActPartDomainLabels();		    
			}
			else
			{
				thisLabel = da.getFunctionLabel();
				nextLabels = da.getNextDialogueActFunctionLabels();
				prevLabels = da.getPreviousDialogueActFunctionLabels();
			}


			String speakerPart = null;
			String otherSpeakerPart = null;

			if (da.getMessage().getSpeaker() == 1)
			{
				speakerPart = "L:";
				otherSpeakerPart = "U:";
			}
			else
			{
				speakerPart = "U:";
				otherSpeakerPart = "L:";
			}

			int thisLabelIndex = labels.indexOf(speakerPart + thisLabel);

			if (thisLabelIndex < 0)
			{
				System.out.println("Error with label: " + thisLabel);
			}
			else
			{
				for (String nextLabel: nextLabels)
				{
					int nextLabelIndex = labels.indexOf(otherSpeakerPart + nextLabel);

					if (nextLabelIndex < 0)
					{
						System.out.println("Error with label: " + nextLabel);
					}
					else
					{
						matrix[thisLabelIndex][nextLabelIndex]++;
					}
				}
			}

			if (prevLabels.isEmpty())
				matrix[labels.indexOf("START1")][thisLabelIndex]++;
		}
		
		for (int i = 0; i < matrix.length; i++)
			for (int j = 0; j < matrix.length; j++)
				grandTotal += matrix[i][j];
			
			
		for (int i = 0; i < matrix.length; i++)
		{
			int total = 0;
			for (int j = 0; j < matrix.length; j++)
				total += matrix[i][j];

			for (int j = 0; j < matrix.length; j++)
			{
				double p = ((double) matrix[i][j]) / total * 100;
				pmatrix[i][j] = (int) Math.round(p);
				tpmatrix[i][j] = (int) Math.round(((double) matrix [i][j]) / grandTotal * 100);
				percentileTotal += tpmatrix[i][j];
			}
		}

		String[] labelArray = new String[labels.size()];
		labelArray = labels.toArray(labelArray);

		System.out.println("Frequencies: ");
		printMatrix(labelArray, matrix);

		System.out.println("Transition-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		System.out.println("Total-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		
		System.out.println("DOT: ");
		printDot(labelArray, tpmatrix, 10, 1, true);
		
		System.out.println("Grand Total: " + grandTotal);
		System.out.println("Pecentile Total: " + percentileTotal);

	}

	public static void speakerNonSenstive(int option)
	{
		DialogueActManager dam = new DialogueActManager();
		DialogueActLabelManager dalm = new DialogueActLabelManager(); 
		DialogueActDimensionManager dadm = new DialogueActDimensionManager();
		MessageManager mm = new MessageManager();
		DialogueActDimension dimension = null;


		if ((option & DOMAIN_PART) != 0)
			dimension = dam.getDialogueActDimension("Domain");
		else
			dimension = dam.getDialogueActDimension("Function");

		List<DialogueActLabel> dialogueActLabels = dam.getDialogueActLabels(dimension, false);

		List<String> labels = new ArrayList<String>();

		if ((option & DOMAIN_PART) != 0)
		{
			for (DialogueActLabel dal: dialogueActLabels)
			{
				String label = dal.getPartLabelNoSpace();
				if (! labels.contains(label))
				{
					System.out.println("Adding " + label + "...");
					labels.add(label);
				}
			}
			labels.add("NA");
		} 
		else
		{
			for (DialogueActLabel dal: dialogueActLabels)
			{
				labels.add(dal.getLabelNoSpace());
				System.out.println("Adding " + dal.getLabel() + "...");
			}
		}

		labels.add("END1");
		labels.add("START1");

		System.out.println(labels.size() + " labels are defined.");

		Collection<DialogueAct> dialogueActs = dam.getDialogueActs(false);

		// Just for testing
		//
		/*
	ConversationManager cm = new ConversationManager();	
	Conversation c1 = cm.getConversation(9);
	Collection<DialogueAct> dialogueActs = new HashSet<DialogueAct>();

	for (Message m: c1.getMessages())
	{
	    dialogueActs.addAll(dam.getDialogueActsByMessage(m, false));
	}
		 */
		// End testing


		int [][] matrix = new int [labels.size()][labels.size()];
		int [][] pmatrix = new int [labels.size()][labels.size()];
		int [][] tpmatrix = new int [labels.size()][labels.size()];

		int count = 0;
		for (DialogueAct da: dialogueActs)
		{
			count++;
			if (true || count % 100 == 0)
			{
				System.out.println(count + " dialogueActs done.."); 
			}
			String thisLabel = null;
			String nextLabel = null;
			String prevLabel = null;

			if ((option & DOMAIN_PART) != 0)
			{
				thisLabel = da.getPartDomainLabel();
				nextLabel = da.getNextDialogueActPartDomainLabel();
				prevLabel = da.getPreviousDialogueActPartDomainLabel();		    
			}
			else
			{
				thisLabel = da.getFunctionLabel();
				nextLabel = da.getNextDialogueActFunctionLabel();
				prevLabel = da.getPreviousDialogueActFunctionLabel();
			}


			int thisLabelIndex = labels.indexOf(thisLabel);
			int nextLabelIndex = labels.indexOf(nextLabel);

			if (thisLabelIndex < 0)
			{
				System.out.println("Error with label: " + thisLabel);
			}
			else if (nextLabelIndex < 0)
			{
				System.out.println("Error with label: " + nextLabel);
			}
			else
			{
				matrix[thisLabelIndex][nextLabelIndex]++;

				if (prevLabel.equals("START1"))
					matrix[labels.indexOf("START1")][thisLabelIndex]++;
			}

		}
        
		int grandTotal = 0;
		for (int i = 0; i < matrix.length; i++)
		{
			int total = 0;
			for (int j = 0; j < matrix.length; j++)
				total += matrix[i][j];

			for (int j = 0; j < matrix.length; j++)
			{
				double p = ((double) matrix[i][j]) / total * 100;
				pmatrix[i][j] = (int) Math.round(p);
				tpmatrix[i][j] = (int) Math.round(((double) matrix [i][j]) / dialogueActs.size() * 100);
				grandTotal+=matrix[i][j];
			}
		}

		String[] labelArray = new String[labels.size()];
		labelArray = labels.toArray(labelArray);

		System.out.println("Frequencies: ");
		printMatrix(labelArray, matrix);

		System.out.println("Transition-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		System.out.println("Total-based Percentiles: ");
		printMatrix(labelArray, tpmatrix);

		
		System.out.println("DOT: ");
		printDot(labelArray, tpmatrix, 20, 5, false);
		
		System.out.println("Grand Total: " + grandTotal);

	}

	public static void printDot(String [] labels, int [][] matrix, int boldCutoff, int cutoff, boolean speakerSensitive)
	{
		System.out.println("digraph G {");

		System.out.println("  size = \"6,6\"");
		System.out.println("  margin = 0");
		System.out.println("  ranksep = 2");
				
		System.out.println("  START1 [label = \"Start\", shape = \"box\"]");
		
		if (speakerSensitive)
		{
			System.out.println("  subgraph cluster_1 {");
			System.out.println("    label = \"User\"");
			for (String label: labels)
			{
				if (label.startsWith(DialogueActLabel.U_PREFIX))
				{
					String node_label = label.replace(DialogueActLabel.U_PREFIX, "").replace('_', ' ');
					System.out.println("    " + label.replace(':', '_') + " [ label =\"" + node_label + "\"]");
				}						
			}
			System.out.println("  }");

			System.out.println("  subgraph cluster_2 {");
			System.out.println("    label = \"Librarian\"");
			for (String label: labels)
			{
				if (label.startsWith(DialogueActLabel.L_PREFIX))
				{
					String node_label = label.replace(DialogueActLabel.L_PREFIX, "").replace('_', ' ');
					System.out.println("    " + label.replace(':', '_') + " [ label =\"" + node_label + "\"]");
				}						
			}
			System.out.println("  }");
		}
		else
		{
			for (String label: labels)
			{
					String node_label = label.replace(DialogueActLabel.L_PREFIX, "").replace('_', ' ');
					System.out.println("    " + label.replace(':', '_') + " [ label =\"" + node_label + "\"]");
			}						
		}
		
		for (int i = 0; i < matrix.length; i++)
		{
			for (int j = 0; j < matrix[0].length; j++)
			{
				if (matrix[i][j] >= cutoff)
				{
					String output = "  " + labels[i].replace(':', '_') + " -> " + labels[j].replace(':', '_') + "[";

					if (matrix[i][j] > boldCutoff)
						output += "style = bold, ";

					output += "label=\"" + matrix[i][j] + "%\"]";

					System.out.println(output);
				}
			}	    
		}
		System.out.println("}");
	}


	public static void printMatrix(String [] labels, int [][] matrix)
	{
		for (int i = 0; i < labels.length; i++)
		{
			System.out.print(", " + labels[i]);
		}
		System.out.println();

		for (int i = 0; i < matrix.length; i++)
		{
			System.out.print(labels[i] + ", ");	    	
			for (int j = 0; j < matrix[0].length; j++)
			{
				System.out.print(matrix[i][j]);
				if (j < labels.length - 1)
					System.out.print(", ");	    	
			}
			System.out.println();
		}			
	}

}
